﻿using LeRenard;
using System;
using System.Collections.Generic;
using Xunit;

namespace LeRenard.Core.Tests._core_._extensions_
{
    public class DateTimeExtensionsTests
    {
            #region IsDay Method Family
            [Fact]
            public void IsDay_Returns_True_On_Correct_DayOfWeek()
            {
                // Arrange
                var expected = true;
                var input = new DateTime(2014, 06, 16, 18, 09, 35);

                // Act
                var actual = input.IsDay(DayOfWeek.Monday);

                // Assert
                Assert.Equal(expected, actual);
            }

            [Fact]
            public void IsDay_Returns_False_On_Incorrect_DayOfWeek()
            {
                // Arrange
                var expected = false;
                var input = new DateTime(2014, 06, 16, 18, 09, 35);

                // Act
                var actual = input.IsDay(DayOfWeek.Tuesday);

                // Assert
                Assert.Equal(expected, actual);
            }

            [Fact]
            public void IsWeekend_Returns_True_On_WeekendDays()
            {
                // Arrange
                var expected = true;
                var input = new List<DateTime>() {
                new DateTime(2014, 06, 14),
                new DateTime(2014, 06, 15)
            };

                // Act
                foreach (var date in input) {
                    var actual = date.IsWeekend();

                    // Assert
                    Assert.Equal(expected, actual);
                }
            }

            [Fact]
            public void IsWeekend_Returns_False_On_WeekDays()
            {
                // Arrange
                var expected = false;
                var input = new List<DateTime>() {
                new DateTime(2014, 06, 16),
                new DateTime(2014, 06, 17),
                new DateTime(2014, 06, 18),
                new DateTime(2014, 06, 19),
                new DateTime(2014, 06, 20)
            };

                // Act
                foreach (var date in input) {
                    var actual = date.IsWeekend();

                    // Assert
                    Assert.Equal(expected, actual);
                }
            }

            [Fact]
            public void IsXxxDay_Returns_True_On_XxxDay()
            {
                // Arrange            
                var expected = true;

                // Act
                // Assert
                Assert.Equal(expected, new DateTime(2014, 06, 16).IsMonday());
                Assert.Equal(expected, new DateTime(2014, 06, 17).IsTuesday());
                Assert.Equal(expected, new DateTime(2014, 06, 18).IsWednesday());
                Assert.Equal(expected, new DateTime(2014, 06, 19).IsThursday());
                Assert.Equal(expected, new DateTime(2014, 06, 20).IsFriday());
                Assert.Equal(expected, new DateTime(2014, 06, 21).IsSaturday());
                Assert.Equal(expected, new DateTime(2014, 06, 22).IsSunday());
            }

            [Fact]
            public void IsXxxDay_Returns_True_On_YyyDay()
            {
                // Arrange            
                var expected = false;

                // Act
                // Assert
                Assert.Equal(expected, new DateTime(2014, 06, 15).IsMonday());
                Assert.Equal(expected, new DateTime(2014, 06, 16).IsTuesday());
                Assert.Equal(expected, new DateTime(2014, 06, 17).IsWednesday());
                Assert.Equal(expected, new DateTime(2014, 06, 18).IsThursday());
                Assert.Equal(expected, new DateTime(2014, 06, 29).IsFriday());
                Assert.Equal(expected, new DateTime(2014, 06, 20).IsSaturday());
                Assert.Equal(expected, new DateTime(2014, 06, 21).IsSunday());
            }

            [Fact]
            public void IsDayIn_Returns_True_On_Correct_DaysOfWeek()
            {
                // Arrange
                var expected = true;
                var input = new DateTime(2014, 06, 16, 18, 09, 35);
                var days = new List<DayOfWeek>() {
                DayOfWeek.Monday, DayOfWeek.Wednesday, DayOfWeek.Friday
            };

                // Act
                var actual = input.IsDayIn(days);

                // Assert
                Assert.Equal(expected, actual);
            }

            [Fact]
            public void IsDayIn_Returns_False_On_Incorrect_DaysOfWeek()
            {
                // Arrange
                var expected = false;
                var input = new DateTime(2014, 06, 16, 18, 09, 35);
                var days = new List<DayOfWeek>() {
                DayOfWeek.Friday, DayOfWeek.Saturday, DayOfWeek.Sunday
            };

                // Act
                var actual = input.IsDayIn(days);

                // Assert
                Assert.Equal(expected, actual);
            }

            [Fact]
            public void IsDayIn_Returns_False_On_Null_DaysOfWeek()
            {
                // Arrange
                var expected = false;
                var input = new DateTime(2014, 06, 16, 18, 09, 35);
                List<DayOfWeek> days = null;

                // Act
                var actual = input.IsDayIn(days);

                // Assert
                Assert.Equal(expected, actual);
            }

            [Fact]
            public void IsDayIn_Returns_False_On_Empty_DaysOfWeek()
            {
                // Arrange
                var expected = false;
                var input = new DateTime(2014, 06, 16, 18, 09, 35);
                var days = new List<DayOfWeek>();

                // Act
                var actual = input.IsDayIn(days);

                // Assert
                Assert.Equal(expected, actual);
            }
            #endregion

            #region "NextDay Method Family"
            [Fact]
            public void NextDay_Returns_Correct_NextDay()
            {
                // Arrange
                var date = new DateTime(2014, 6, 17, 10, 28, 30);
                var expected = new DateTime(2014, 6, 18, 10, 28, 30);

                // Act            
                var actual = date.NextDay();

                // Assert
                Assert.Equal(expected, actual);
            }

            [Fact]
            public void PreviousDay_Returns_Correct_PreviousDay()
            {
                // Arrange
                var date = new DateTime(2014, 6, 17, 10, 28, 30);
                var expected = new DateTime(2014, 6, 16, 10, 28, 30);

                // Act            
                var actual = date.PreviousDay();

                // Assert
                Assert.Equal(expected, actual);
            }

            [Fact]
            public void NextDay_DayOfWeek_Returns_Correct_NextDay()
            {
                // Arrange
                var date = new DateTime(2014, 6, 17, 10, 28, 30);
                var expected = new DateTime(2014, 6, 20, 10, 28, 30);

                // Act            
                var actual = date.NextDay(DayOfWeek.Friday);

                // Assert
                Assert.Equal(expected, actual);
            }

            [Fact]
            public void NextDay_DayOfWeek_Returns_Correct_NextDay_7DaysForward()
            {
                // Arrange
                var date = new DateTime(2014, 6, 17, 10, 28, 30);
                var expected = new DateTime(2014, 6, 24, 10, 28, 30);

                // Act            
                var actual = date.NextDay(DayOfWeek.Tuesday);

                // Assert
                Assert.Equal(expected, actual);
            }

            [Fact]
            public void PreviousDay_DayOfWeek_Returns_Correct_PreviousDay()
            {
                // Arrange
                var date = new DateTime(2014, 6, 17, 10, 28, 30);
                var expected = new DateTime(2014, 6, 11, 10, 28, 30);

                // Act            
                var actual = date.PreviousDay(DayOfWeek.Wednesday);

                // Assert
                Assert.Equal(expected, actual);
            }

            [Fact]
            public void PreviousDay_DayOfWeek_Returns_Correct_PreviousDay_7DaysAgo()
            {
                // Arrange
                var date = new DateTime(2014, 6, 17, 10, 28, 30);
                var expected = new DateTime(2014, 6, 10, 10, 28, 30);

                // Act            
                var actual = date.PreviousDay(DayOfWeek.Tuesday);

                // Assert
                Assert.Equal(expected, actual);
            }

            [Fact]
            public void NextDay_DayOfWeek_Bulk_Test()
            {
                // Arrange
                var date = new DateTime(2014, 6, 15, 10, 58, 44); // starting on sunday

                for (int i = 1;
                i <= 7;
                i++) {
                    // Act
                    var expected = date.AddDays(i);
                    var actual = date.PreviousDay((DayOfWeek)i);

                    // Assert
                    DateTime.Equals(expected, actual);
                }
            }

            [Fact]
            public void PreviousDay_DayOfWeek_Bulk_Test()
            {
                // Arrange
                var date = new DateTime(2014, 6, 15, 10, 58, 44); // starting on sunday

                for (int i = 1;
                i <= 7;
                i++) {
                    // Act
                    var expected = date.AddDays(i * -1);
                    var actual = date.PreviousDay((DayOfWeek)i);

                    // Assert
                    DateTime.Equals(expected, actual);
                }
            }
            #endregion        
    }
}
